#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
PyQt6 Socket客户端页面
提供TCP/UDP客户端连接和Modbus TCP/RTU设备连接功能，发送HEX命令采集数据
"""

from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
                             QGroupBox, QPushButton, QLabel, QLineEdit,
                             QComboBox, QRadioButton, QScrollArea,
                             QFrame, QApplication, QTextEdit)
from PyQt6.QtCore import pyqtSignal, Qt
from PyQt6.QtGui import QFont
import serial.tools.list_ports

from utils.communication import TcpClientManager
from gui.components.pyqt6_log_component import PyQt6LogComponent  # 使用统一的日志组件


class SocketClientPage(QWidget):
    """Socket客户端页面类"""
    
    def __init__(self):
        """初始化Socket客户端页面"""
        super().__init__()
        self.title = "Socket客户端"
        
        # 初始化通信管理器
        self.tcp_client_manager = TcpClientManager(self._client_message_callback)
        
        # 初始化界面
        self._init_ui()
    
    def _init_ui(self):
        """初始化UI界面"""
        # 设置主布局
        main_layout = QHBoxLayout(self)
        main_layout.setContentsMargins(15, 15, 15, 15)
        main_layout.setSpacing(15)
        
        # 左侧控制面板
        control_panel = self._create_control_panel()
        main_layout.addWidget(control_panel, 1)
        
        # 右侧日志面板
        log_panel = self._create_log_panel()
        main_layout.addWidget(log_panel, 3)
        
        # 设置整体样式
        self._setup_styles()
    
    def _create_control_panel(self):
        """创建控制面板"""
        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)
        scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        
        container = QWidget()
        layout = QVBoxLayout(container)
        layout.setSpacing(15)
        
        # 服务器协议选择
        server_protocol_group = QGroupBox("服务器协议")
        server_protocol_layout = QVBoxLayout(server_protocol_group)
        
        self.tcp_server_radio = QRadioButton("TCP服务器")
        self.udp_server_radio = QRadioButton("UDP服务器")
        self.tcp_server_radio.setChecked(True)
        
        server_protocol_layout.addWidget(self.tcp_server_radio)
        server_protocol_layout.addWidget(self.udp_server_radio)
        
        # 服务器连接配置
        server_group = QGroupBox("服务器连接")
        server_layout = QGridLayout(server_group)
        server_layout.setSpacing(10)
        
        server_layout.addWidget(QLabel("服务器IP:"), 0, 0)
        self.server_ip_edit = QLineEdit("127.0.0.1")
        server_layout.addWidget(self.server_ip_edit, 0, 1)
        
        server_layout.addWidget(QLabel("端口:"), 1, 0)
        self.server_port_edit = QLineEdit("9010")
        server_layout.addWidget(self.server_port_edit, 1, 1)
        
        self.server_connect_btn = QPushButton("连接服务器")
        self.server_connect_btn.clicked.connect(self._connect_server)
        server_layout.addWidget(self.server_connect_btn, 2, 0, 1, 2)
        
        # Modbus协议选择
        modbus_protocol_group = QGroupBox("Modbus协议")
        modbus_protocol_layout = QVBoxLayout(modbus_protocol_group)
        
        self.tcp_modbus_radio = QRadioButton("Modbus TCP")
        self.rtu_modbus_radio = QRadioButton("Modbus RTU")
        self.tcp_modbus_radio.setChecked(True)
        
        self.tcp_modbus_radio.toggled.connect(self._on_modbus_protocol_change)
        self.rtu_modbus_radio.toggled.connect(self._on_modbus_protocol_change)
        
        modbus_protocol_layout.addWidget(self.tcp_modbus_radio)
        modbus_protocol_layout.addWidget(self.rtu_modbus_radio)
        
        # Modbus设备连接配置
        self.modbus_config_group = QGroupBox("Modbus设备连接 (TCP)")
        self.modbus_config_layout = QGridLayout(self.modbus_config_group)
        self.modbus_config_layout.setSpacing(10)
        
        # 创建TCP配置控件（默认显示）
        self._create_modbus_tcp_config()
        
        self.modbus_connect_btn = QPushButton("连接Modbus设备")
        self.modbus_connect_btn.clicked.connect(self._connect_modbus_device)
        self.modbus_config_layout.addWidget(self.modbus_connect_btn, 10, 0, 1, 2)
        
        # 状态显示
        status_group = QGroupBox("状态信息")
        status_layout = QVBoxLayout(status_group)
        
        self.server_status_label = QLabel("服务器: 未连接")
        self.modbus_status_label = QLabel("Modbus设备: 未连接")
        
        status_layout.addWidget(self.server_status_label)
        status_layout.addWidget(self.modbus_status_label)
        
        # 数据发送组
        send_group = QGroupBox("数据发送")
        send_layout = QVBoxLayout(send_group)
        send_layout.setSpacing(10)
        
        send_layout.addWidget(QLabel("HEX命令:"))
        self.send_data_edit = QLineEdit("01 03 00 00 00 06")
        self.send_data_edit.setStyleSheet("""
            QLineEdit {
                padding: 8px;
                border: 1px solid #ccc;
                border-radius: 4px;
            }
        """)
        send_layout.addWidget(self.send_data_edit)
        
        self.send_data_btn = QPushButton("发送HEX命令")
        self.send_data_btn.setStyleSheet("""
            QPushButton {
                background-color: #4CAF50;
                color: white;
                border: none;
                padding: 10px;
                border-radius: 4px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton:pressed {
                background-color: #3d8b40;
            }
        """)
        self.send_data_btn.clicked.connect(self._send_data)
        send_layout.addWidget(self.send_data_btn)
        
        # 添加到主布局
        layout.addWidget(server_protocol_group)
        layout.addWidget(server_group)
        layout.addWidget(modbus_protocol_group)
        layout.addWidget(self.modbus_config_group)
        layout.addWidget(status_group)
        layout.addWidget(send_group)
        layout.addStretch()
        
        scroll_area.setWidget(container)
        return scroll_area
    
    def _setup_styles(self):
        """设置界面样式"""
        # 设置字体
        font = QFont("Arial", 10)
        self.setFont(font)

        # 为所有控件设置统一字体
        # for widget in self.findChildren(QWidget):
        #     if isinstance(widget, (QLabel, QLineEdit, QPushButton, QTextEdit)):
        #         widget.setFont(font)

        # 为所有GroupBox设置样式
        for group_box in self.findChildren(QGroupBox):
            group_box.setStyleSheet("""
                QGroupBox {
                    font-weight: bold;
                    border: 1px solid gray;
                    border-radius: 5px;
                    margin-top: 1ex;
                }
                QGroupBox::title {
                    subline-offset: -2px;
                    padding: 0 5px;
                }
            """)
    
    def _create_modbus_tcp_config(self):
        """创建Modbus TCP配置控件"""
        # 清空配置布局
        for i in reversed(range(self.modbus_config_layout.count())):
            self.modbus_config_layout.itemAt(i).widget().setParent(None)
        
        self.modbus_config_group.setTitle("Modbus设备连接 (TCP)")
        
        # IP地址
        self.modbus_config_layout.addWidget(QLabel("设备IP:"), 0, 0)
        self.modbus_ip_edit = QLineEdit("127.0.0.1")
        self.modbus_config_layout.addWidget(self.modbus_ip_edit, 0, 1)
        
        # 端口
        self.modbus_config_layout.addWidget(QLabel("端口:"), 1, 0)
        self.modbus_port_edit = QLineEdit("5020")
        self.modbus_config_layout.addWidget(self.modbus_port_edit, 1, 1)
        
        # 连接按钮
        self.modbus_connect_btn = QPushButton("连接Modbus设备")
        self.modbus_connect_btn.clicked.connect(self._connect_modbus_device)
        self.modbus_config_layout.addWidget(self.modbus_connect_btn, 10, 0, 1, 2)
    
    def _create_modbus_rtu_config(self):
        """创建Modbus RTU配置控件"""
        # 清空配置布局
        for i in reversed(range(self.modbus_config_layout.count())):
            self.modbus_config_layout.itemAt(i).widget().setParent(None)
        
        self.modbus_config_group.setTitle("Modbus设备连接 (RTU)")
        
        # 串口
        self.modbus_config_layout.addWidget(QLabel("串口:"), 0, 0)
        self.rtu_port_combo = QComboBox()
        self.modbus_config_layout.addWidget(self.rtu_port_combo, 0, 1)
        
        # 波特率
        self.modbus_config_layout.addWidget(QLabel("波特率:"), 1, 0)
        self.rtu_baudrate_combo = QComboBox()
        self.rtu_baudrate_combo.addItems(['9600', '19200', '38400', '57600', '115200'])
        self.rtu_baudrate_combo.setCurrentText('9600')
        self.modbus_config_layout.addWidget(self.rtu_baudrate_combo, 1, 1)
        
        # 数据位
        self.modbus_config_layout.addWidget(QLabel("数据位:"), 2, 0)
        self.rtu_bytesize_combo = QComboBox()
        self.rtu_bytesize_combo.addItems(['7', '8'])
        self.rtu_bytesize_combo.setCurrentText('8')
        self.modbus_config_layout.addWidget(self.rtu_bytesize_combo, 2, 1)
        
        # 校验位
        self.modbus_config_layout.addWidget(QLabel("校验位:"), 3, 0)
        self.rtu_parity_combo = QComboBox()
        self.rtu_parity_combo.addItems(['N', 'E', 'O'])
        self.rtu_parity_combo.setCurrentText('N')
        self.modbus_config_layout.addWidget(self.rtu_parity_combo, 3, 1)
        
        # 停止位
        self.modbus_config_layout.addWidget(QLabel("停止位:"), 4, 0)
        self.rtu_stopbits_combo = QComboBox()
        self.rtu_stopbits_combo.addItems(['1', '2'])
        self.rtu_stopbits_combo.setCurrentText('1')
        self.modbus_config_layout.addWidget(self.rtu_stopbits_combo, 4, 1)
        
        # 刷新串口按钮
        refresh_btn = QPushButton("刷新串口")
        refresh_btn.clicked.connect(self._refresh_rtu_ports)
        self.modbus_config_layout.addWidget(refresh_btn, 5, 0, 1, 2)
        
        # 连接按钮
        self.modbus_connect_btn = QPushButton("连接Modbus设备")
        self.modbus_connect_btn.clicked.connect(self._connect_modbus_device)
        self.modbus_config_layout.addWidget(self.modbus_connect_btn, 10, 0, 1, 2)
        
        # 刷新串口列表
        self._refresh_rtu_ports()
    
    def _refresh_rtu_ports(self):
        """刷新RTU串口列表"""
        try:
            ports = [port.device for port in serial.tools.list_ports.comports()]
            self.rtu_port_combo.clear()
            self.rtu_port_combo.addItems(ports)
        except Exception as e:
            self.log_component.log_message(f"刷新串口列表失败: {e}", "ERROR")
    
    def _create_log_panel(self):
        """创建日志面板"""
        self.log_component = PyQt6LogComponent(self, "客户端日志", 20)
        return self.log_component
    
    def _on_modbus_protocol_change(self):
        """Modbus协议切换事件处理"""
        if self.tcp_modbus_radio.isChecked():
            self._create_modbus_tcp_config()
        else:
            self._create_modbus_rtu_config()
    
    def _connect_server(self):
        """连接服务器"""
        try:
            protocol = "TCP" if self.tcp_server_radio.isChecked() else "UDP"
            ip = self.server_ip_edit.text().strip()
            port = int(self.server_port_edit.text().strip())
            
            if self.tcp_client_manager.connect_server(protocol, ip, port):
                self.server_status_label.setText(f"服务器: 已连接{protocol} {ip}:{port}")
                self.server_connect_btn.setText("断开服务器")
                self.server_connect_btn.clicked.disconnect()
                self.server_connect_btn.clicked.connect(self._disconnect_server)
                self.log_component.log_message(f"连接{protocol}服务器成功: {ip}:{port}")
            else:
                self.log_component.log_message(f"连接{protocol}服务器失败", "ERROR")
                
        except Exception as e:
            self.log_component.log_message(f"连接服务器失败: {e}", "ERROR")
    
    def _disconnect_server(self):
        """断开服务器连接"""
        try:
            self.tcp_client_manager.disconnect_server()
            self.server_status_label.setText("服务器: 未连接")
            self.server_connect_btn.setText("连接服务器")
            self.server_connect_btn.clicked.disconnect()
            self.server_connect_btn.clicked.connect(self._connect_server)
            self.log_component.log_message("已断开服务器连接")
        except Exception as e:
            self.log_component.log_message(f"断开服务器连接错误: {e}", "ERROR")
    
    def _connect_modbus_device(self):
        """连接Modbus设备"""
        try:
            if self.tcp_modbus_radio.isChecked():
                ip = self.modbus_ip_edit.text().strip()
                port = int(self.modbus_port_edit.text().strip())
                
                if self.tcp_client_manager.connect_modbus_device(ip, port):
                    self.modbus_status_label.setText(f"Modbus设备: 已连接TCP {ip}:{port}")
                    self.modbus_connect_btn.setText("断开Modbus设备")
                    self.modbus_connect_btn.clicked.disconnect()
                    self.modbus_connect_btn.clicked.connect(self._disconnect_modbus_device)
                    self.log_component.log_message(f"连接Modbus TCP设备成功: {ip}:{port}")
                else:
                    self.log_component.log_message("连接Modbus TCP设备失败", "ERROR")
            else:  # RTU
                port = self.rtu_port_combo.currentText().strip()
                baudrate = int(self.rtu_baudrate_combo.currentText())
                bytesize = int(self.rtu_bytesize_combo.currentText())
                parity = self.rtu_parity_combo.currentText()
                stopbits = int(self.rtu_stopbits_combo.currentText())
                
                if not port:
                    self.log_component.log_message("请选择串口", "WARNING")
                    return
                
                if self.tcp_client_manager.connect_modbus_rtu_device(port, baudrate, bytesize, parity, stopbits):
                    self.modbus_status_label.setText(f"Modbus设备: 已连接RTU {port}@{baudrate}")
                    self.modbus_connect_btn.setText("断开Modbus设备")
                    self.modbus_connect_btn.clicked.disconnect()
                    self.modbus_connect_btn.clicked.connect(self._disconnect_modbus_device)
                    self.log_component.log_message(f"连接Modbus RTU设备成功: {port}@{baudrate}")
                else:
                    self.log_component.log_message("连接Modbus RTU设备失败", "ERROR")
                
        except Exception as e:
            self.log_component.log_message(f"连接Modbus设备失败: {e}", "ERROR")
    
    def _disconnect_modbus_device(self):
        """断开Modbus设备连接"""
        try:
            self.tcp_client_manager.disconnect_modbus_device()
            self.modbus_status_label.setText("Modbus设备: 未连接")
            self.modbus_connect_btn.setText("连接Modbus设备")
            self.modbus_connect_btn.clicked.disconnect()
            self.modbus_connect_btn.clicked.connect(self._connect_modbus_device)
            self.log_component.log_message("已断开Modbus设备连接")
        except Exception as e:
            self.log_component.log_message(f"断开Modbus设备连接错误: {e}", "ERROR")
    
    def _send_data(self):
        """发送数据"""
        cmd_str = self.send_data_edit.text().strip()
        if not cmd_str:
            self.log_component.log_message("请输入要发送的HEX命令", "WARNING")
            return
        
        try:
            # 检查连接状态
            status = self.tcp_client_manager.get_connection_status()
            
            if not any(status.values()):
                self.log_component.log_message("请先连接服务器或Modbus设备", "WARNING")
                return
            
            if self.tcp_client_manager.send_command(cmd_str):
                self.log_component.log_message(f"发送HEX命令: {cmd_str}", "INFO", "send")
            else:
                self.log_component.log_message("发送HEX命令失败", "ERROR")
                
        except Exception as e:
            self.log_component.log_message(f"发送数据失败: {e}", "ERROR")
    
    def _client_message_callback(self, message: str, level: str = "INFO", msg_type: str = "normal"):
        """客户端消息回调"""
        self.log_component.log_message(message, level, msg_type)
    
    def on_close(self):
        """页面关闭时的清理"""
        try:
            self.tcp_client_manager.disconnect_server()
            self.tcp_client_manager.disconnect_modbus()
        except:
            pass


if __name__ == "__main__":
    from PyQt6.QtWidgets import QApplication
    import sys
    
    app = QApplication(sys.argv)
    window = SocketClientPage()
    window.show()
    sys.exit(app.exec())